package com.smart.community.user.controller;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.smart.community.commons.annotation.ApiLog;
import com.smart.community.commons.enums.ApiLogOperationType;
import com.smart.community.commons.enums.RoleCodeEnum;
import com.smart.community.commons.enums.UserTypeEnum;
import com.smart.community.commons.result.Result;
import com.smart.community.user.constant.MessageConstants;
import com.smart.community.user.dto.LoginDTO;
import com.smart.community.user.dto.AppLoginDTO;
import com.smart.community.user.dto.RegisterDTO;
import com.smart.community.user.dto.ChangePasswordDTO;
import com.smart.community.user.entity.Permission;
import com.smart.community.user.entity.UserRole;
import com.smart.community.user.service.AuthService;
import com.smart.community.user.service.CaptchaService;
import com.smart.community.user.service.PermissionService;
import com.smart.community.user.service.UserRoleService;
import com.smart.community.user.service.RoleService;
import com.smart.community.user.vo.LoginVO;
import com.smart.community.user.vo.AppLoginVO;
import com.smart.community.user.vo.RoleVO;
import com.smart.community.user.vo.UserVO;

import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.stp.StpUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import com.smart.community.commons.utils.SecurityUtils;

/**
 * 用户认证控制器
 * 
 * @author Wu.Liang
 */
@RestController
@RequestMapping("/user/auth")
@Tag(name = "用户认证", description = "用户登录、注册、认证相关接口")
@Slf4j
public class AuthController {

	@Autowired
	private AuthService authService;

	@Autowired
	private CaptchaService captchaService;

	@Autowired
	private PermissionService permissionService;

	@Autowired
	private UserRoleService userRoleService;

	@Autowired
	private RoleService roleService;

	/**
	 * 用户登录
	 * 
	 * @author Wu.Liang
	 */
	@PostMapping("/login")
	@Operation(summary = "用户登录")
	public Result<LoginVO> login(@RequestBody @Valid LoginDTO loginDTO) throws Exception {
		// 直接调用Service，异常统一抛出，不捕获处理
		// 验证验证码
		if (loginDTO.getCaptcha() != null && loginDTO.getCaptchaKey() != null) {
			if (!captchaService.verifyImageCaptcha(loginDTO.getCaptchaKey(), loginDTO.getCaptcha())) {
				return Result.businessError(MessageConstants.CAPTCHA_ERROR);
			}
		}

		// 执行登录
		LoginVO loginVO = authService.login(loginDTO);
		return Result.success(MessageConstants.LOGIN_SUCCESS, loginVO);
	}

	/**
	 * App端用户登录（带身份验证）
	 * 
	 * @author Wu.Liang
	 */
	@PostMapping("/app/login")
	@Operation(summary = "App端用户登录")
	public Result<AppLoginVO> appLogin(@RequestBody @Valid AppLoginDTO appLoginDTO) throws Exception {
		// 验证登录身份类型参数
		if (appLoginDTO.getLoginIdentityType() == null) {
			log.warn("App端登录失败：登录身份类型参数不能为空，用户名: {}", appLoginDTO.getUsername());
			return Result.businessError("登录身份类型不能为空");
		}
		
		// 验证登录身份类型值是否有效
		if (appLoginDTO.getLoginIdentityType() < 1 || appLoginDTO.getLoginIdentityType() > 3) {
			log.warn("App端登录失败：登录身份类型参数无效，用户名: {}，身份类型: {}", 
				appLoginDTO.getUsername(), appLoginDTO.getLoginIdentityType());
			return Result.businessError("登录身份类型参数无效，请选择正确的身份类型");
		}
		
		// 直接调用Service，异常统一抛出，不捕获处理
		// 验证验证码
		if (appLoginDTO.getCaptcha() != null && appLoginDTO.getCaptchaKey() != null) {
			if (!captchaService.verifyImageCaptcha(appLoginDTO.getCaptchaKey(), appLoginDTO.getCaptcha())) {
				return Result.businessError(MessageConstants.CAPTCHA_ERROR);
			}
		}

		// 执行App登录
		AppLoginVO appLoginVO = authService.appLogin(appLoginDTO);
		return Result.success("App登录成功", appLoginVO);
	}

	/**
	 * 用户登出
	 * 
	 * @author Wu.Liang
	 */
	@PostMapping("/logout")
	@Operation(summary = "用户登出")
	@SaCheckLogin
	public Result<Void> logout() throws Exception {
		// 直接调用Service，异常统一抛出，不捕获处理
		authService.logout();
		return Result.success(MessageConstants.LOGOUT_SUCCESS, null);
	}

	/**
	 * 刷新Token
	 * 
	 * @author Wu.Liang
	 */
	@PostMapping("/refresh")
	@Operation(summary = "刷新Token")
	public Result<String> refreshToken() throws Exception {
		// 直接调用Service，异常统一抛出，不捕获处理
		String newToken = authService.refreshToken();
		return Result.success(MessageConstants.TOKEN_REFRESH_SUCCESS, newToken);
	}

	/**
	 * 获取当前用户信息
	 * 
	 * @author Wu.Liang
	 */
	@GetMapping("/info")
	@Operation(summary = "获取当前用户信息")
	@SaCheckLogin
	public Result<UserVO> getCurrentUser() throws Exception {
		// 直接调用Service，异常统一抛出，不捕获处理
		UserVO userVO = authService.getCurrentUser();
		return Result.success(MessageConstants.QUERY_SUCCESS, userVO);
	}

	/**
	 * 生成图形验证码
	 * 
	 * @author Wu.Liang
	 */
	@GetMapping("/captcha/image")
	@Operation(summary = "生成图形验证码")
	public Result<CaptchaService.CaptchaInfo> generateImageCaptcha() throws Exception {
		// 直接调用Service，异常统一抛出，不捕获处理
		CaptchaService.CaptchaInfo captchaInfo = captchaService.generateImageCaptcha();
		return Result.success(MessageConstants.SUCCESS, captchaInfo);
	}

	/**
	 * 发送短信验证码
	 * 
	 * @author Wu.Liang
	 */
	@PostMapping("/captcha/sms")
	@Operation(summary = "发送短信验证码")
	public Result<Void> sendSmsCaptcha(@RequestParam String phone) throws Exception {
		// 直接调用Service，异常统一抛出，不捕获处理
		captchaService.sendSmsCaptcha(phone);
		return Result.success("短信验证码发送成功", null);
	}

	/**
	 * 发送邮箱验证码
	 * 
	 * @author Wu.Liang
	 */
	@PostMapping("/captcha/email")
	@Operation(summary = "发送邮箱验证码")
	public Result<Void> sendEmailCaptcha(@RequestParam String email) throws Exception {
		// 直接调用Service，异常统一抛出，不捕获处理
		captchaService.sendEmailCaptcha(email);
		return Result.success("邮箱验证码发送成功", null);
	}

	/**
	 * 检查登录状态
	 * 
	 * @author Wu.Liang
	 */
	@GetMapping("/check")
	@Operation(summary = "检查登录状态")
	public Result<Boolean> checkLoginStatus() throws Exception {
		// 直接调用Service，异常统一抛出，不捕获处理
		boolean isLoggedIn = authService.isLoggedIn();
		return Result.success(MessageConstants.QUERY_SUCCESS, isLoggedIn);
	}

	/**
	 * 用户注册
	 * 
	 * @author Wu.Liang
	 */
	@ApiLog(logTitle = "用户注册", logType = 2, moduleName = "用户管理", operationType = ApiLogOperationType.ADD)
	@PostMapping("/register")
	@Operation(summary = "用户注册")
	public Result<Void> register(@RequestBody @Valid RegisterDTO registerDTO) throws Exception {
		// 直接调用Service，异常统一抛出，不捕获处理
		// 验证验证码
		if (registerDTO.getCaptcha() != null && registerDTO.getCaptchaKey() != null) {
			if (!captchaService.verifyImageCaptcha(registerDTO.getCaptchaKey(), registerDTO.getCaptcha())) {
				return Result.businessError(MessageConstants.CAPTCHA_ERROR);
			}
		}

		// 验证密码确认
		if (!registerDTO.getPassword().equals(registerDTO.getConfirmPassword())) {
			return Result.businessError("两次输入的密码不一致");
		}

		// 执行注册
		authService.register(registerDTO);
		return Result.success(MessageConstants.REGISTER_SUCCESS, null);
	}

	/**
	 * 修改密码
	 * 
	 * @author Wu.Liang
	 */
	@ApiLog(logTitle = "修改密码", logType = 2, moduleName = "用户管理", operationType = ApiLogOperationType.UPDATE)
	@PostMapping("/password/change")
	@Operation(summary = "修改密码")
	@SaCheckLogin
	public Result<Void> changePassword(@RequestBody @Valid ChangePasswordDTO changePasswordDTO) {
		try {
			log.info("开始修改密码，用户ID: {}", changePasswordDTO.getUserId());
			
			authService.changePassword(changePasswordDTO.getUserId(), changePasswordDTO.getOldPassword(),
					changePasswordDTO.getNewPassword());
			
			log.info("密码修改成功，用户ID: {}", changePasswordDTO.getUserId());
			return Result.success(MessageConstants.PASSWORD_CHANGE_SUCCESS, null);
		} catch (Exception e) {
			log.error("修改密码失败，用户ID: {}, 错误信息: {}", changePasswordDTO.getUserId(), e.getMessage(), e);
			return Result.fail("修改密码失败：" + e.getMessage());
		}
	}

	/**
	 * 发送重置密码邮件
	 * 
	 * @author Wu.Liang
	 */
	@PostMapping("/password/reset/email")
	@Operation(summary = "发送重置密码邮件")
	public Result<Void> sendResetPasswordEmail(@RequestParam String email) throws Exception {
		// 直接调用Service，异常统一抛出，不捕获处理
		authService.sendResetPasswordEmail(email);
		return Result.success("重置密码邮件发送成功", null);
	}

	/**
	 * 重置密码
	 * 
	 * @author Wu.Liang
	 */
	@ApiLog(logTitle = "重置密码", logType = 2, moduleName = "用户管理", operationType = ApiLogOperationType.UPDATE)
	@PostMapping("/password/reset")
	@Operation(summary = "重置密码")
	public Result<Void> resetPassword(@RequestParam String token, @RequestParam String newPassword) throws Exception {
		// 直接调用Service，异常统一抛出，不捕获处理
		// 验证重置Token
		if (!authService.validateResetToken(token)) {
			return Result.businessError("重置Token无效或已过期");
		}

		// 从当前认证上下文获取用户ID
		Long userId = SecurityUtils.getCurrentUserId();
		if (userId == null) {
			return Result.fail("无法获取当前用户信息");
		}
		authService.resetPassword(userId, newPassword);

		return Result.success("密码重置成功", null);
	}

	/**
	 * Token验证接口 - 供网关调用 网关通过此接口验证Token并获取用户信息
	 * 
	 * @author Wu.Liang
	 */
	@PostMapping("/verify-token")
	@Operation(summary = "Token验证接口")
	public Result<Map<String, Object>> verifyToken(@RequestParam String token) throws Exception {
		// 直接调用Service，异常统一抛出，不捕获处理
		log.debug("网关调用Token验证接口: {}", token);

		// 验证Token有效性
		try {
			// 使用Sa-Token验证Token
			StpUtil.setTokenValue(token, 0);
			if (!StpUtil.isLogin()) {
				log.warn("Token验证失败: {}", token);
				return Result.businessError("Token无效");
			}
		} catch (Exception e) {
			log.warn("Token验证异常: {}", e.getMessage());
			return Result.businessError("Token验证失败");
		}

		// 获取当前登录用户ID
		Long userId = StpUtil.getLoginIdAsLong();

		// 获取用户信息
		UserVO userVO = authService.getCurrentUser();
		if (userVO == null) {
			log.warn("未找到用户信息，用户ID: {}", userId);
			return Result.businessError("未找到用户信息");
		}

		// 获取用户权限和角色
		List<String> permissions = new ArrayList<>();
		List<String> roles = new ArrayList<>();

		try {
			// 获取用户权限
			List<Permission> permissionList = permissionService.getPermissionsByUserId(userId);
			if (permissionList != null) {
				permissions = permissionList.stream().filter(p -> p != null && p.getPermissionCode() != null)
						.map(p -> p.getPermissionCode()).collect(Collectors.toList());
			}

			// 获取用户角色
			List<UserRole> userRoleList = userRoleService.getUserRolesByUserId(userId);
			if (userRoleList != null && !userRoleList.isEmpty()) {
				for (UserRole ur : userRoleList) {
					if (ur != null && ur.getRoleId() != null) {
						RoleVO roleVO = roleService.getRole(ur.getRoleId());
						if (roleVO != null && roleVO.getRoleCode() != null) {
							roles.add(roleVO.getRoleCode());
						}
					}
				}
			}

			// 超级管理员特殊处理
			boolean isSuperAdmin = false;
			for (String roleCode : roles) {
				if (RoleCodeEnum.SUPER_ADMIN.getCode().equals(roleCode)) {
					isSuperAdmin = true;
					break;
				}
			}
			if ("admin".equals(userVO.getUsername()) || isSuperAdmin) {
				roles = new ArrayList<>();
				roles.add(RoleCodeEnum.SUPER_ADMIN.getCode());
				// 正确设置超级管理员的用户类型
				userVO.setUserType(UserTypeEnum.SUPER_ADMIN.getCode());

				// 获取所有菜单权限
				List<String> allMenuPermissions = new ArrayList<>();
				try {
					List<Permission> allPerms = permissionService.list();
					for (Permission p : allPerms) {
						if (p != null && p.getPermissionCode() != null
								&& ("MENU".equals(p.getType()) || p.getType() == null) && p.getStatus() != null
								&& p.getStatus() == 1 && (p.getDeleted() == null || p.getDeleted() == 0)) {
							allMenuPermissions.add(p.getPermissionCode());
						}
					}
				} catch (Exception e) {
					log.warn("查询全部菜单权限失败", e);
				}
				permissions = new ArrayList<>(allMenuPermissions);
				permissions.add("*:*:*");
			}

		} catch (Exception e) {
			log.warn("获取用户权限或角色失败，用户ID: {}", userId, e);
		}

		// 构建返回结果
		Map<String, Object> result = new HashMap<>();
		result.put("userId", userVO.getId());
		result.put("username", userVO.getUsername());
		result.put("realName", userVO.getRealName());
		result.put("userType", userVO.getUserType());
		result.put("roles", roles);
		result.put("permissions", permissions);
		result.put("token", token);

		// 判断是否为超级管理员
		boolean isSuperAdmin = roles.contains(RoleCodeEnum.SUPER_ADMIN.getCode());
		result.put("superAdmin", isSuperAdmin);

		log.info("Token验证成功，用户信息: userId={}, username={}, roles={}, permissions={}", userVO.getId(),
				userVO.getUsername(), roles, permissions);

		return Result.success("Token验证成功", result);
	}
}